﻿using IWshRuntimeLibrary;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
using System.Xml;

namespace Autoupdate.Common
{
    public static class Util
    {
        public static void CreateShortcut(string directory, string shortcutName, string targetPath,
            string description = null, string iconLocation = null)
        {
            if (!System.IO.Directory.Exists(directory))
                System.IO.Directory.CreateDirectory(directory);

            string shortcutPath = Path.Combine(directory, string.Format("{0}.lnk", shortcutName));
            WshShell shell = new WshShell();
            IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(shortcutPath);//创建快捷方式对象
            shortcut.TargetPath = targetPath;//指定目标路径
            shortcut.WorkingDirectory = Path.GetDirectoryName(targetPath);//设置起始位置
            shortcut.WindowStyle = 1;//设置运行方式，默认为常规窗口
            shortcut.Description = description;//设置备注
            shortcut.IconLocation = string.IsNullOrWhiteSpace(iconLocation) ? targetPath : iconLocation;//设置图标路径
            shortcut.Save();//保存快捷方式
        }

        ///// <summary>
        ///// 创建桌面快捷方式
        ///// </summary>
        ///// <param name="shortcutName">快捷方式名称</param>
        ///// <param name="targetPath">目标路径</param>
        ///// <param name="description">描述</param>
        ///// <param name="iconLocation">图标路径，格式为"可执行文件或DLL路径, 图标编号"</param>
        ///// <remarks></remarks>
        //public static void CreateShortcutOnDesktop(string shortcutName, string targetPath,
        //    string description = null, string iconLocation = null)
        //{
        //    string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);//获取桌面文件夹路径
        //    CreateShortcut(desktop, shortcutName, targetPath, description, iconLocation);
        //}

        public static void FindFiles(string path, ref List<string> files)
        {
            DirectoryInfo folder = new DirectoryInfo(path + "\\");
            foreach (DirectoryInfo dir in folder.GetDirectories())
                FindFiles(path + "\\" + dir.ToString(), ref files);
            foreach (FileInfo file in folder.GetFiles())
                files.Add(path + "\\" + file.ToString());
        }

        public static string GetFileMD5(byte[] buffer)
        {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            md5.ComputeHash(buffer);

            byte[] b = md5.Hash;
            md5.Clear();

            StringBuilder sb = new StringBuilder(32);
            for (int i = 0; i < b.Length; i++)
            {
                sb.Append(b[i].ToString("X2"));
            }

            return sb.ToString();
        }

        public static string GetFileMD5(string filePath)
        {
            FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);

            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            md5.ComputeHash(fs);
            fs.Close();

            byte[] b = md5.Hash;
            md5.Clear();

            StringBuilder sb = new StringBuilder(32);
            for (int i = 0; i < b.Length; i++)
            {
                sb.Append(b[i].ToString("X2"));
            }

            return sb.ToString();
        }

        /// <summary> 
        /// 将 Stream 转成 byte[] 
        /// </summary> 
        public static byte[] StreamToBytes(Stream stream)
        {
            byte[] bytes = new byte[stream.Length];
            stream.Read(bytes, 0, bytes.Length);
            // 设置当前流的位置为流的开始 
            stream.Seek(0, SeekOrigin.Begin);
            return bytes;
        }
        /// <summary> 
        /// 将 byte[] 转成 Stream 
        /// </summary> 
        public static Stream BytesToStream(byte[] bytes)
        {
            Stream stream = new MemoryStream(bytes);
            return stream;
        }

        /* - - - - - - - - - - - - - - - - - - - - - - - - 
        * Stream 和 文件之间的转换 
        * - - - - - - - - - - - - - - - - - - - - - - - */
        /// <summary> 
        /// 将 Stream 写入文件 
        /// </summary> 
        public static void StreamToFile(Stream stream, string fileName)
        {
            // 把 Stream 转换成 byte[] 
            byte[] bytes = new byte[stream.Length];
            stream.Read(bytes, 0, bytes.Length);
            // 设置当前流的位置为流的开始 
            stream.Seek(0, SeekOrigin.Begin);
            // 把 byte[] 写入文件 
            FileStream fs = new FileStream(fileName, FileMode.Create);
            BinaryWriter bw = new BinaryWriter(fs);
            bw.Write(bytes);
            bw.Close();
            fs.Close();
            stream.Close();
        }
        /// <summary> 
        /// 从文件读取 Stream 
        /// </summary> 
        public static Stream FileToStream(string fileName)
        {
            // 打开文件 
            FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
            // 读取文件的 byte[] 
            byte[] bytes = new byte[fileStream.Length];
            fileStream.Read(bytes, 0, bytes.Length);
            fileStream.Close();
            // 把 byte[] 转换成 Stream 
            Stream stream = new MemoryStream(bytes);
            return stream;
        }

        public static string GetRelativePath(string basePath, string path)
        {
            string[] baseValues = basePath.Split(new char[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
            string[] values = path.Split(new char[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
            int count = Math.Min(baseValues.Length, values.Length);
            if (count == 0)
                return path;
            int index = -1;
            for (int i = 0; i < count; ++i)
            {
                if (baseValues[i].ToUpper() == values[i].ToUpper())
                    index = i;
                else
                    break;
            }
            if (index == -1)
                return path;
            string relativePath = string.Empty;
            for (int i = index + 1; i < baseValues.Length; ++i)
                relativePath += (".." + Path.DirectorySeparatorChar);

            for (int i = index + 1; i < values.Length; ++i)
            {
                if (!string.IsNullOrEmpty(relativePath))
                    relativePath += Path.DirectorySeparatorChar;
                relativePath += values[i];
            }
            return relativePath;
        }

        // 0 - 9 对应十进制 48-57
        // a - z 对应十进制 97-122
        // A - Z 对应十进制 65-90
        public static bool IsNumeric(string str)
        {
            if (string.IsNullOrEmpty(str))
                return false;
            ASCIIEncoding ascii = new ASCIIEncoding();
            byte[] byteStr = ascii.GetBytes(str);
            foreach (byte c in byteStr)
            {
                if (c < 48 || c > 57)
                    return false;
            }
            return true;
        }

        public static int ToMillisecond(string second)
        {
            return (int)(Convert.ToDouble(second) * 1000.0f);
        }

        public static string FormatString(string strInput, int fractionalCount)
        {
            string outPut = strInput;
            int index = outPut.IndexOf(".");
            if (index == -1)
                return outPut;
            if (fractionalCount == 0)
                return outPut.Substring(0, index);
            if (index + fractionalCount + 1 > outPut.Length)
                return outPut;
            return outPut.Substring(0, index + fractionalCount + 1);
        }

        public static void Delay(int millisecond)
        {
            int start = Environment.TickCount;
            while (Math.Abs(Environment.TickCount - start) < millisecond)
                Application.DoEvents();
        }

        public static void DataTableToXml(DataTable table, string path)
        {
            StreamWriter sw = new StreamWriter(path, false);
            sw.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
            sw.WriteLine("<DataTable>");
            // 列数据
            sw.WriteLine("\t<Columns>");
            for (int i = 0; i < table.Columns.Count; ++i)
                sw.WriteLine("\t\t<Column name = \"" + table.Columns[i].ColumnName + "\"/>");
            sw.WriteLine("\t</Columns>");
            // 行数据
            for (int i = 0; i < table.Rows.Count; ++i)
            {
                sw.WriteLine("\t<Row>");
                for (int j = 0; j < table.Columns.Count; ++j)
                    sw.WriteLine("\t\t<" + table.Columns[j].ColumnName + ">"
                        + table.Rows[i][j].ToString()
                        + "</" + table.Columns[j].ColumnName + ">");
                sw.WriteLine("\t</Row>");
            }
            sw.WriteLine("</DataTable>");
            sw.Close();
        }

        public static bool XmlToDataTable(string path, ref DataTable table)
        {
            FileInfo fi = new FileInfo(path);
            if (!fi.Exists)
            {
                Log.WriteError("Util.XmlToDataTable", "文件 '" + path + "' 不存在.");
                return false;
            }

            table.Rows.Clear();

            XmlReader reader = new XmlTextReader(path);
            XmlDocument doc = new XmlDocument();
            doc.Load(reader);
            XmlNode root = doc.DocumentElement;
            XmlNodeList nodelist = root.SelectNodes("Columns/Column");
            if (NeedClearColumn(nodelist, table))
            {
                table.Rows.Clear();
                table.Columns.Clear();
                foreach (XmlNode node in nodelist)
                {
                    XmlNode columnNode = node.SelectSingleNode("@name");
                    if (columnNode == null)
                    {
                        Log.WriteError("Util.XmlToDataTable",
                            "读取文件 '" + path + "' 时找不到属性名name.");
                        reader.Close();
                        return false;
                    }
                    table.Columns.Add(columnNode.InnerText);
                }
            }

            nodelist = root.SelectNodes("Row");
            foreach (XmlNode node in nodelist)
            {
                DataRow newRow = table.NewRow();
                foreach (DataColumn column in table.Columns)
                {
                    XmlNode dataNode = node.SelectSingleNode(column.ColumnName);
                    if (dataNode == null)
                    {
                        Log.WriteError("Util.XmlToDataTable",
                            "读取文件 '" + path + "' 时找不到结点 '" + column.ColumnName + "'.");
                        reader.Close();
                        return false;
                    }
                    newRow[column.ColumnName] = dataNode.InnerText;
                }
                table.Rows.Add(newRow);
            }
            reader.Close();
            return true;
        }

        private static bool NeedClearColumn(XmlNodeList nodelist, DataTable table)
        {
            if (nodelist.Count != table.Columns.Count)
                return true;

            foreach (XmlNode node in nodelist)
            {
                XmlNode columnNode = node.SelectSingleNode("@name");
                if (columnNode == null)
                    return true;
                if (!table.Columns.Contains(columnNode.InnerText))
                    return true;
            }

            return false;
        }
    }
}
